/**
 * @file bsp_button.c
 * @brief 按键封装驱动
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2020-08-14
 * @copyright Copyright (c) 2020  烽火通信
 ***************************************************************
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version  <th>Author  <th>Description
 * <tr><td>2020-08-14 <td>1.0      <td>wangh   <td>内容
 * </table>
 */ 

#ifdef __cplusplus
extern "C" {
#endif 
#include "bsp_button.h"
#include "bsp_error.h"

#if USE_BSP_BUTTON
#undef LOG_LEVEL_
#define LOG_LEVEL_ 	LOG_LVL_ASSERT
#include "bsp_log.h"


static Button_t m_buttons[16];      ///< 最多支持16个按键，每个按键exit需不一样

static uint16_t m_pin_state;        ///< 引脚状态（高低）
static uint16_t m_pin_transition;   ///< 引脚变化


/**
 * @brief 按键检测延时超时处理函数
 */
static void detection_delay_timeout_ind(TimerHandle_t xTimer)
{
    Button_t *p_btn = (Button_t *)pvTimerGetTimerID(xTimer);
    
    uint16_t btn_mask = 1 << p_btn->pin_no;
    if (btn_mask & m_pin_transition)
    {
        m_pin_transition &= ~btn_mask;
        
        uint8_t pin_state = GpioRead(&p_btn->btn_gpio);
        
        if ( (m_pin_state & (1 << p_btn->pin_no)) == (pin_state << p_btn->pin_no) )
        {
            uint8_t transition = !(pin_state ^ (p_btn->active_state == BUTTON_ACTIVE_HIGH));

            if (p_btn->button_handler)
            {
                p_btn->button_handler(p_btn->pin_no, transition);
            }
        }
    }
}

/**
 * @brief IO中断回调函数
 * @param[in] pin 引脚编号(0~15)
 */
static void GPIO_EXTI_Callback(uint8_t pin)
{
    uint16_t pin_mask = 1 << pin;

    xTimerStop(m_buttons[pin].btn_timer, 0);

    if (!(m_pin_transition & pin_mask)) /* 有变化 */
    {
        if (GpioRead(&m_buttons[pin].btn_gpio))
        {
            m_pin_state |= pin_mask;    /* 引脚状态1 */
        }
        else
        {
            m_pin_state &= ~(pin_mask); /* 引脚状态0 */
        }
        m_pin_transition |= (pin_mask);

        xTimerReset(m_buttons[pin].btn_timer, 0);
    }
    else
    {
        m_pin_transition &= ~pin_mask;
    }
}

/**
 * @brief 按键初始化
 * @param[in]  p_gpio       gpio句柄
 * @param[in]  pin          引脚
 * @param[in]  type         上下拉类型 @ref PIN_NO_PULL @ref PIN_PULL_UP @ref PIN_PULL_DOWN
 * @param[in]  active_state 按键有效值 @ref BUTTON_ACTIVE_HIGH @ref BUTTON_ACTIVE_LOW
 * @param[in]  detection_delay 按键检测延时时间(ms)
 * @param[in]  btn_handle   按键事件处理回调
 * @return int8_t 
 * - @b Sucess : @ref BSP_SUCCESS \n
 * - @b Fail
 * - @ref BSP_ERROR_INVALID_PARAM - 非法入参
 * - @ref BSP_ERROR_NO_MEM - 内存不足
 */
int8_t button_init(Gpio_t *p_gpio, PinNames pin, PinTypes type, uint8_t active_state, uint16_t detection_delay, button_handler_t btn_handle)
{
    if ( (p_gpio == NULL) || (pin == NC) || (active_state > 2) || (btn_handle == NULL) )
        return BSP_ERROR_INVALID_PARAM;

    m_buttons[pin&0x0F].pin_no = pin&0x0F;
    m_buttons[pin&0x0F].button_handler = btn_handle;
    m_buttons[pin&0x0F].active_state = active_state;
    
    GpioInit( p_gpio, pin, PIN_INPUT, PIN_PUSH_PULL, type, 2 );
    GpioSetInterrupt( p_gpio, IRQ_RISING_FALLING_EDGE, IRQ_HIGH_PRIORITY, GPIO_EXTI_Callback );
    
    m_buttons[pin&0x0F].btn_gpio = *p_gpio;

    m_buttons[pin&0x0F].btn_timer = xTimerCreate("btn", detection_delay * portTICK_RATE_MS, pdFALSE, &m_buttons[pin&0x0F], detection_delay_timeout_ind);
    if(m_buttons[pin&0x0F].btn_timer == NULL)
    {
        log_e("button%d btn_timer create error\r\n", pin&0x0F);
        return BSP_ERROR_NO_MEM;
    }

    return BSP_SUCCESS;
}

#endif	/* USE_BSP_BUTTON */
#ifdef __cplusplus
}
#endif //__cplusplus 

/*********** (C) COPYRIGHT 2020 FiberHome *****END OF FILE****/
